using System;
using System.Diagnostics;
using System.Linq;

namespace rsync
{
    /// <summary>
    /// 终端每一帧的输入二进制数据，需要自己解析为具体的输入类型
    /// </summary>
    internal class InputData
    {
        /// <summary>
        /// 空输入，没有任何操作
        /// </summary>
        public const int NullFrame = -1;

        /// <summary>
        /// 每一个玩家输入的大小
        /// </summary>
        public readonly uint InputSize;
        
        /// <summary>
        /// 玩家的数量
        /// </summary>
        public readonly uint PlayerCount;
        
        /// <summary>
        /// 输入产生的所在帧数
        /// </summary>
        public int Frame;
        
        /// <summary>
        /// 终端输入组成的二进制数据
        /// </summary>
        public byte[] Inputs;

        /// <summary>
        /// 终端在frame帧产生的输入
        /// </summary>
        /// <param name="frame">帧id</param>
        /// <param name="inputSize">单个玩家输入产生的二进制输入大小</param>
        /// <param name="playerCount">该终端的玩家数量</param>
        public InputData(int frame, uint inputSize, uint playerCount)
        {
            Frame = frame;
            Inputs = new byte[inputSize * playerCount];
            InputSize = inputSize;
            PlayerCount = playerCount;
        }

        /// <summary>
        /// 通过复制生产一个输入数据
        /// </summary>
        /// <param name="inputData">被复制的输入</param>
        public InputData(InputData inputData) : this(inputData.Frame, inputData.InputSize, inputData.PlayerCount)
        {
            Array.Copy(inputData.Inputs, Inputs, inputData.Inputs.Length);
        }

        /// <summary>
        /// 把deviceInputs数据整个的复制过来
        /// </summary>
        /// <param name="playerOffset">起始偏移offset个InputSize</param>
        /// <param name="playerCount">deviceInputs的玩家数量</param>
        /// <param name="deviceInputs">二进制输入数据</param>
        public void SetInputs(uint playerOffset, uint playerCount, byte[] deviceInputs)
        {
            Debug.Assert(deviceInputs != null);
            Debug.Assert(playerOffset + (playerCount * InputSize) <= Inputs.Length);
            Debug.Assert(deviceInputs.Length == playerCount * InputSize);

            Array.Copy(deviceInputs, 0, Inputs, playerOffset * InputSize, deviceInputs.Length);
        }

        public bool Equal(InputData other, bool inputsOnly)
        {
            if (!inputsOnly && Frame != other.Frame)
            {
                Console.WriteLine("frames don't match: {0}, {1}", Frame, other.Frame);
            }
            if (InputSize != other.InputSize)
            {
                Console.WriteLine("inputsize for a single player doesn't match: {0}, {1}", InputSize, other.InputSize);
            }
            if (Inputs.Length != other.Inputs.Length)
            {
                Console.WriteLine("inputs array length don't match: {0}, {1}", Inputs.Length, other.Inputs.Length);
            }
            if (!Inputs.SequenceEqual(other.Inputs))
            {
                Console.WriteLine("inputs don't match\n");
            }
            Debug.Assert(Inputs.Length > 0 && other.Inputs.Length > 0);
            return (inputsOnly || Frame == other.Frame) &&
                   Inputs.Length == other.Inputs.Length &&
                   InputSize == other.InputSize &&
                   Inputs.SequenceEqual(other.Inputs);
        }
    }
}
